﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Threading;
using System.Collections.Generic;
using System.Diagnostics;

namespace System.Windows.Media.DirectShow
{
    public class SingleThreadPool : IDisposable
    {

        private Thread thread;
        private ManualResetEvent workEvent = new ManualResetEvent(false);
        private Queue<Job> jobs = new Queue<Job>();
        private bool exit;

        public SingleThreadPool()
        {
            PrepareThread();
        }

        private void PrepareThread()
        {
            thread = new Thread(Run);
            thread.Start();
        }

        public void QueueUserWorkItem(WaitCallback callBack, object state)
        {
            lock (jobs)
            {
                jobs.Enqueue(new Job
                {
                    Callback = callBack,
                    State = state,
                });
            }
            workEvent.Set();
        }

        private void Run()
        {
            while (!exit)
            {
                if (exit) break;
                if (jobs.Count == 0)
                {
                    workEvent.WaitOne();
                    workEvent.Reset();
                }
                if (exit) break;

                if (jobs.Count > 0)
                {
                    // Get new job
                    Job job;
                    lock (jobs)
                        job = jobs.Dequeue();

                    try
                    {
                        if (exit) break;
                        job.Callback(job.State);
                    }
                    catch (ThreadAbortException)
                    { }
                    catch (Exception e)
                    {
                        Debug.WriteLine(e);
                    }
                }
            }
        }

        ~SingleThreadPool()
        {
            this.Dispose(false);
        }

        public void Dispose()
        {
            this.Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                exit = true;
                jobs.Clear();
                workEvent.Set();
                if (thread != null)
                    thread.Abort();
            }
            thread = null;
        }

        protected internal class Job
        {
            public object State { get; set; }
            public WaitCallback Callback { get; set; }
        }


        public void Abort()
        {
            try
            {
                exit = true;
                workEvent.Set();
                thread.Join(500);
            }         
            catch
            { }
            finally
            {
                exit = false;
            }
            workEvent.Reset();
            jobs.Clear();
            PrepareThread();
        }
    }
}
